package cn.caishen.report.controller;

import cn.caishen.report.common.constant.LbConstant;
import cn.caishen.report.common.exceptions.BusinessException;
import cn.caishen.report.common.exceptions.ResponseResult;
import cn.caishen.report.common.utils.ExcelUtil;
import cn.caishen.report.common.utils.IntegerUtil;
import cn.caishen.report.common.utils.LbMap;
import cn.caishen.report.domain.report.ReportChart;
import cn.caishen.report.domain.system.Module;
import cn.caishen.report.service.report.ReportChartService;
import cn.caishen.report.service.report.ReportChartWhereService;
import cn.caishen.report.service.report.ReportConfigService;
import cn.caishen.report.service.system.ModuleService;
import com.github.pagehelper.util.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;

/**
 * 动态报表控制层
 *
 * @author LB
 * @description 动态报表控制层
 */
@RestController
@RequestMapping(value = "/report")
@Slf4j
@Api(tags = "动态报表")
public class ReportController {

    private final ReportConfigService reportConfigService;
    private final ReportChartService reportChartService;
    private final ModuleService moduleService;

    public ReportController(ReportConfigService reportConfigService, ModuleService moduleService, ReportChartService reportChartService) {
        this.reportConfigService = reportConfigService;
        this.moduleService = moduleService;
        this.reportChartService = reportChartService;
    }

    /**
     * 查询菜单
     *
     * @return
     */
    @GetMapping(value = "/getBusinessType", name = "查询菜单")
    @ApiOperation("查询菜单")
    public LbMap getBusinessType() {
        try {
            List<Module> moduleList = moduleService.list();
            log.info("查询菜单成功");
            return ResponseResult.success("查询菜单成功", moduleList, moduleList.size());
        } catch (BusinessException e) {
            log.info("查询菜单失败：", e);
            return ResponseResult.fail("查询菜单失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("查询菜单失败：", e);
            return ResponseResult.fail("查询菜单失败");
        }
    }

    /**
     * 根据模块查找报表内容
     *
     * @param moduleId
     * @return
     */
    @GetMapping(value = "/getModuleReport", name = "根据模块查找报表内容")
    @ApiOperation("根据模块查找报表内容(包含标题列表、条件列表)")
    public LbMap getModuleReport(Integer moduleId) {
        try {
            if (IntegerUtil.isEmpty(moduleId)) {
                return ResponseResult.fail("报表查询失败，未找到模块编号");
            }

            LbMap resultMap = reportConfigService.getModuleReport(moduleId, 0);
            log.info("根据模块查找报表内容成功");
            return ResponseResult.success("根据模块查找报表内容成功", resultMap);
        } catch (BusinessException e) {
            log.info("模块对应报表查询失败：", e);
            return ResponseResult.fail("模块对应报表查询失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("模块对应报表查询失败：", e);
            return ResponseResult.fail("模块对应报表查询失败");
        }
    }


    /**
     * 查找报表明细配置内容
     *
     * @param detailReportConfigId
     * @return
     */
    @GetMapping(value = "/getDetailReport", name = "查找报表明细配置内容")
    @ApiOperation("查找报表明细配置内容")
    public LbMap getDetailReport(Integer detailReportConfigId) {
        try {
            if (Objects.isNull(detailReportConfigId)) {
                return ResponseResult.fail("报表查询失败，未找到报表配置编号");
            }

            LbMap resultMap = reportConfigService.getModuleReport(0, detailReportConfigId);
            log.info("查找报表明细配置内容成功");
            return ResponseResult.success("查找报表明细配置内容成功", resultMap);
        } catch (BusinessException e) {
            log.info("查找报表明细配置内容失败：", e);
            return ResponseResult.fail("查找报表明细配置内容失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("查找报表明细配置内容失败：", e);
            return ResponseResult.fail("查找报表明细配置内容失败");
        }
    }


    /**
     * 查询动态报表公共方法
     *
     * @param param
     * @return
     */
    @PostMapping(value = "/getReportList", name = "查询动态报表")
    @ApiOperation("查询动态报表公共方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "param", value = "参数，以json格式接收，必须含有 {moduleId:xxx}，选择包含 {page:xxx, limit:xxx}，条件参数都以json格式传入", required = true,
                    example = "{moduleId:1, page:1, limit:10}")
    })
    public LbMap getReportList(@RequestBody LbMap param) {
        try {
            if (Objects.isNull(param)) {
                return ResponseResult.fail("报表查询失败，未找到参数");
            }
            int moduleId = param.getInt("moduleId");
            int detailReportConfigId = param.getInt("detailReportConfigId");

            if (moduleId == 0 && detailReportConfigId == 0) {
                return ResponseResult.fail("报表查询失败，未找到模块编号或明细报表编号");
            }

            int page = param.getInt("page");
            if (page == 0) {
                page = 1;
            }

            int limit = param.getInt("limit");
            if (limit == 0) {
                limit = 10;
            }

            LbMap resultMap = reportConfigService.getReportList(param, moduleId, detailReportConfigId, page, limit, param.getString("selectFields"),
                    param.getString("orderFields"), param.getString("groupFields"), "");
            log.info("报表查询成功");
            return ResponseResult.success("报表查询成功", resultMap);
        } catch (BusinessException e) {
            log.info("报表查询失败：", e);
            return ResponseResult.fail("报表查询失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("报表查询失败：", e);
            return ResponseResult.fail("报表查询失败");
        }
    }

    /**
     * 查询动态报表总合计行
     *
     * @param param
     * @return
     */
    @PostMapping(value = "/getReportSum", name = "查询动态报表总合计行")
    @ApiOperation("查询动态报表总合计行")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "param", value = "参数，以json格式接收，必须含有 {moduleId:xxx}，选择包含 {page:xxx, limit:xxx}，条件参数都以json格式传入", required = true,
                    example = "{moduleId:1}")
    })
    public LbMap getReportSum(@RequestBody LbMap param) {
        try {
            if (Objects.isNull(param)) {
                return ResponseResult.fail("查询动态报表总合计行失败，未找到参数");
            }
            int moduleId = param.getInt("moduleId");
            int detailReportConfigId = param.getInt("detailReportConfigId");

            if (moduleId == 0 && detailReportConfigId == 0) {
                return ResponseResult.fail("查询动态报表总合计行失败，未找到模块编号或明细报表编号");
            }

            LbMap resultMap = reportConfigService.getReportList(param, moduleId, detailReportConfigId, 0, 0, true,
                    param.getString("selectFields"), param.getString("orderFields"), "", "");
            log.info("查询动态报表总合计行成功");
            return ResponseResult.success("查询动态报表总合计行成功", resultMap);
        } catch (BusinessException e) {
            log.info("查询动态报表总合计行失败：", e);
            return ResponseResult.fail("查询动态报表总合计行失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("查询动态报表总合计行失败：", e);
            return ResponseResult.fail("查询动态报表总合计行失败");
        }
    }


    /**
     * 动态报表导出EXCEL公共方法
     *
     * @param param
     * @return
     */
    @PostMapping(value = "/reportToExcel", name = "动态报表导出EXCEL")
    @ApiOperation("动态报表导出EXCEL公共方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "param", value = "参数，以json格式接收，必须含有 {moduleId:xxx, fileName:xxx}，选择包含 {page:xxx, limit:xxx}，条件参数都以json格式传入", required = true,
                    example = "{moduleId:1, fileName:采购订单明细}")
    })
    public LbMap reportToExcel(HttpServletResponse response, @RequestBody LbMap param) {
        try {
            if (Objects.isNull(param)) {
                throw new BusinessException("未找到参数");
            }

            int moduleId = param.getInt("moduleId");
            int detailReportConfigId = param.getInt("detailReportConfigId");

            if (moduleId == 0 && detailReportConfigId == 0) {
                return ResponseResult.fail("动态报表导出EXCEL失败，未找到模块编号或明细报表编号");
            }

            String fileName = param.getString("fileName");
            if (StringUtil.isEmpty(fileName)) {
                throw new BusinessException("导出文件名称不能为空");
            }

            LbMap reportMap = reportConfigService.getReportList(param, moduleId, detailReportConfigId, 0, 0, param.getString("selectFields"),
                    param.getString("orderFields"), param.getString("groupFields"), "");
            reportMap.put(LbConstant.FILE_NAME, fileName);
            XSSFWorkbook wb = reportConfigService.reportToExcel(reportMap);

            ExcelUtil.download(wb, response, fileName);
            log.info("动态报表导出EXCEL成功");
            return ResponseResult.success("动态报表导出EXCEL成功");
        } catch (BusinessException e) {
            log.info("动态报表导出EXCEL失败：", e);
            return ResponseResult.fail("动态报表导出EXCEL失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("动态报表导出EXCEL失败：", e);
            return ResponseResult.fail("动态报表导出EXCEL失败");
        }
    }


    /**
     * 图形显示时，获取坐标轴
     *
     * @param moduleId
     * @return
     */
    @PostMapping(value = "/getReportAxis", name = "图形显示时，获取坐标轴")
    @ApiOperation("图形显示时，获取坐标轴")
    public LbMap getReportAxis(Integer moduleId) {
        try {
            if (IntegerUtil.isEmpty(moduleId)) {
                return ResponseResult.fail("报表查询失败，未找到模块编号");
            }

            LbMap map = reportConfigService.getReportAxis(moduleId);

            log.info("获取坐标轴成功");
            return ResponseResult.success("获取坐标轴成功", map);
        } catch (BusinessException e) {
            log.info("获取坐标轴失败：", e);
            return ResponseResult.fail("获取坐标轴失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("获取坐标轴失败：", e);
            return ResponseResult.fail("获取坐标轴失败");
        }
    }


    /**
     * 获取图形报表数据
     *
     * @param param
     * @return
     */
    @PostMapping(value = "/getReportAxisList", name = "获取图形报表数据")
    @ApiOperation("获取图形报表数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "param", value = "参数，以json格式接收，必须含有 {moduleId:xxx, xParam:xxx, yParam:xxx}，选择包含 {page:xxx, limit:xxx}，条件参数都以json格式传入", required = true,
                    example = "{moduleId:1, xParam:xField, yParam:yField}")
    })
    public LbMap getReportAxisList(@RequestBody LbMap param) {
        try {
            if (Objects.isNull(param)) {
                throw new BusinessException("未找到参数");
            }

            int moduleId = param.getInt("moduleId");
            if (moduleId == 0) {
                throw new BusinessException("未找到模块编号");
            }

            String xParam = param.getString("xParam");
            if (StringUtil.isEmpty(xParam)) {
                throw new BusinessException("x对象不能为空");
            }

            String yParam = param.getString("yParam");
            if (StringUtil.isEmpty(yParam)) {
                throw new BusinessException("y对象不能为空");
            }

            /*String zParam = param.getString("zParam");
            if (StringUtil.isEmpty(zParam)) {
                throw new BusinessException("z对象不能为空");
            }*/

            String lastSql = "";
            /*if (param.getInt("ranking") == 1) {
                lastSql = " limit 15 ";
            }*/
            int reportChartId = param.getInt("reportChartId");
            int needTotal = 0;
            int ranking = 0;
            ReportChart reportChart = reportChartService.getById(reportChartId);
            if (Objects.nonNull(reportChart)) {
                //检查看板上的图形是否显示合计
                needTotal = reportChart.getNeedTotal();
                ranking = (reportChart.getChartType().equals(LbConstant.CHART_TYPE.RANKING_LIST.getCode())) ? 1 : 0;
            }

            if ("".equals(param.getString(LbConstant.RANKING_FIELD))) {
                //当看板上显示排行榜时，写死10位排行
                param.put(LbConstant.RANKING_FIELD, ranking);
                param.put(LbConstant.RANKING_COUNT_FIELD, 10);
            } else {
                //当图形显示时，显示6位排行
                param.put(LbConstant.RANKING_COUNT_FIELD, LbConstant.REPORT_RANKING_COUNT);
            }

            param.put("needTotal", needTotal);
            LbMap reportMap = reportConfigService.getReportList(param, moduleId, 0, 0, 0, "",
                    param.getString("orderFields"), "", lastSql);
            LbMap axisMap = reportConfigService.getReportAxisList(reportMap.getList(LbConstant.DATA_LIST), xParam, yParam, "", param);
            axisMap.put("reportChart", reportChart);

            log.info("获取图形报表数据成功");
            return ResponseResult.success("获取图形报表数据成功", axisMap);
        } catch (BusinessException e) {
            log.info("获取图形报表数据失败：", e);
            return ResponseResult.fail("获取图形报表数据失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("获取图形报表数据失败：", e);
            return ResponseResult.fail("获取图形报表数据失败");
        }
    }

    /**
     * 获取看板配置
     *
     * @return
     */
    @PostMapping(value = "/getReportChart", name = "获取看板配置")
    @ApiOperation("获取看板配置")
    public LbMap getReportChart(Integer moduleId) {
        try {
            if (IntegerUtil.isEmpty(moduleId)) {
                throw new BusinessException("未找到看板对应的模块编号");
            }
            List<ReportChart> reportChartList = reportConfigService.getReportChart(moduleId);
            LbMap resultMap = reportConfigService.getReportChartWhere(moduleId);
            resultMap.put("reportChartList", reportChartList);
            log.info("获取看板配置成功");
            return ResponseResult.success("获取看板配置成功", resultMap);
        } catch (BusinessException e) {
            log.info("获取看板配置失败：", e);
            return ResponseResult.fail("获取看板配置失败：" + e.getMessage());
        } catch (Exception e) {
            log.info("获取看板配置失败：", e);
            return ResponseResult.fail("获取看板配置失败");
        }
    }
}
